package tests;

import network.Device;
import network.Network;
import network.Rule;

import java.util.HashMap;

public class F16Constructor {
    private static int links = 0;
    private static Network n = new Network();
    private static HashMap<Integer, String> deviceToName = new HashMap<>();

    private static void addLink(int x, String xs, int y) {
        links ++;
        n.addLink(deviceToName.get(x), deviceToName.get(x) + xs, deviceToName.get(y), deviceToName.get(y));
    }

    public static Network getNetwork() {
        n.addDevice("default");

        int server_l = 0, server_r = 48 * 48;
        int fsw_l = server_r, fsw_r = fsw_l + 16 * 48;
        int ssw_l = fsw_r, ssw_r = ssw_l + 16 * 48;

        for (int i = server_l; i < ssw_r; i ++) {
            deviceToName.put(i, "sw" + i);
            n.addDevice(deviceToName.get(i));
        }

        for (String name : deviceToName.values()) {
            n.addLink(name, "default", "default", name + "-peer-default");
        }

        for (int serverId = server_l; serverId < server_r; serverId ++) {
            int pod = (serverId - server_l) / 48;
            for (int spinePlane = 0; spinePlane < 16; spinePlane ++) {
                int fswId = fsw_l + pod * 16 + spinePlane;
                addLink(serverId, "-up", fswId);
                addLink(fswId, "-down" + serverId, serverId);
            }
        }

        for (int sswId = ssw_l; sswId < ssw_r; sswId ++) {
            int spinePlane = (sswId - ssw_l) / 48;
            for (int pod = 0; pod < 48; pod ++) {
                int fswId = fsw_l + pod * 16 + spinePlane;
                addLink(fswId, "-up", sswId);
                addLink(sswId, "-down" + pod, fswId);
            }
        }

        Rule rule;
        Device device;
        String name;
        for (int dst = server_l; dst < server_r; dst ++) {
            int podDst = (dst - server_l) / 48;
            for (int sw = server_l; sw < server_r; sw ++) {
                if (sw != dst) {
                    name = deviceToName.get(sw);
                    device = n.getNameToDevice().get(name);
                    rule = new Rule(device, dst, 32, device.getPortByName(name + "up"));
                    n.addInitialRules(rule);
                }
            }
            for (int sw = fsw_l; sw < fsw_l; sw ++) {
                int pod = (sw - fsw_l) / 16;
                // int spinePlane = (sw - fsw_l) % 16;
                name = deviceToName.get(sw);
                device = n.getNameToDevice().get(name);
                if (podDst == pod) {
                    rule = new Rule(device, dst, 32, device.getPortByName(name + "down" + dst));
                } else {
                    rule = new Rule(device, dst, 32, device.getPortByName(name + "up"));
                }
                n.addInitialRules(rule);
            }
            for (int sw = ssw_l; sw < ssw_r; sw ++) {
                name = deviceToName.get(sw);
                device = n.getNameToDevice().get(name);
                rule = new Rule(device, dst, 32, device.getPortByName(name + "down" +podDst));
                n.addInitialRules(rule);
            }
        }

        System.out.println("# egress ports = " + links);
        System.out.println("# rules = " + n.getInitialRules().size());
        return n;
    }
}
